package ${packagePrefix}.common.exception;

import ${packagePrefix}.common.api.ApiResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.sql.SQLException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

<#if generateComments>
/**
 * 全局异常处理器
 * <p>
 * 处理系统所有异常，统一异常响应格式。
 * 异常处理的顺序是从具体到抽象，先处理特定的业务异常，然后是各种框架异常，
 * 最后处理一般的运行时异常和未知异常。
 * </p>
 * 
 * @author Auto Generated
 */
</#if>
@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 处理业务异常
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ApiResponse<Void> handleBusinessException(BusinessException e, HttpServletRequest request) {
        log.warn("业务异常: {}", e.getMessage());
        return ApiResponse.fail(e.getErrorCode(), e.getMessage())
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    /**
     * 处理数据不存在异常
     */
    @ExceptionHandler(DataNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ApiResponse<Void> handleDataNotFoundException(DataNotFoundException e, HttpServletRequest request) {
        log.warn("数据不存在: {}", e.getMessage());
        return ApiResponse.fail(e.getErrorCode(), e.getMessage())
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    /**
     * 处理数据已存在异常
     */
    @ExceptionHandler(DuplicateDataException.class)
    @ResponseStatus(HttpStatus.CONFLICT)
    public ApiResponse<Void> handleDuplicateDataException(DuplicateDataException e, HttpServletRequest request) {
        log.warn("数据重复: {}", e.getMessage());
        return ApiResponse.fail(e.getErrorCode(), e.getMessage())
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    /**
     * 处理数据验证异常
     */
    @ExceptionHandler(InvalidDataException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ApiResponse<Void> handleInvalidDataException(InvalidDataException e, HttpServletRequest request) {
        log.warn("数据无效: {}", e.getMessage());
        return ApiResponse.fail(e.getErrorCode(), e.getMessage())
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    /**
     * 处理权限不足异常
     */
    @ExceptionHandler(PermissionDeniedException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public ApiResponse<Void> handlePermissionDeniedException(PermissionDeniedException e, HttpServletRequest request) {
        log.warn("权限不足: {}", e.getMessage());
        return ApiResponse.fail(e.getErrorCode(), e.getMessage())
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    /**
     * 处理认证异常
     */
    @ExceptionHandler(AuthenticationException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public ApiResponse<Void> handleAuthenticationException(AuthenticationException e, HttpServletRequest request) {
        log.warn("认证失败: {}", e.getMessage());
        return ApiResponse.fail(e.getErrorCode(), e.getMessage())
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    /**
     * 处理外部系统调用异常
     */
    @ExceptionHandler(ExternalSystemException.class)
    @ResponseStatus(HttpStatus.BAD_GATEWAY)
    public ApiResponse<Void> handleExternalSystemException(ExternalSystemException e, HttpServletRequest request) {
        log.error("外部系统调用异常: {}", e.getMessage(), e);
        return ApiResponse.fail(e.getErrorCode(), e.getMessage())
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    /**
     * 处理并发操作异常
     */
    @ExceptionHandler(ConcurrentOperationException.class)
    @ResponseStatus(HttpStatus.CONFLICT)
    public ApiResponse<Void> handleConcurrentOperationException(ConcurrentOperationException e, HttpServletRequest request) {
        log.warn("并发操作冲突: {}", e.getMessage());
        return ApiResponse.fail(e.getErrorCode(), e.getMessage())
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    /**
     * 处理操作不允许异常
     */
    @ExceptionHandler(OperationNotAllowedException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public ApiResponse<Void> handleOperationNotAllowedException(OperationNotAllowedException e, HttpServletRequest request) {
        log.warn("操作不允许: {}", e.getMessage());
        return ApiResponse.fail(e.getErrorCode(), e.getMessage())
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    /**
     * 处理文件操作异常
     */
    @ExceptionHandler(FileOperationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ApiResponse<Void> handleFileOperationException(FileOperationException e, HttpServletRequest request) {
        log.warn("文件操作异常: {}", e.getMessage());
        return ApiResponse.fail(e.getErrorCode(), e.getMessage())
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    // ================ 框架异常处理 ================
    
    /**
     * 处理数据绑定异常
     */
    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ApiResponse<Void> handleBindException(BindException e, HttpServletRequest request) {
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        String message = fieldErrors.stream()
                .map(error -> error.getField() + ": " + error.getDefaultMessage())
                .collect(Collectors.joining(", "));
        log.warn("参数绑定异常: {}", message);
        return ApiResponse.fail(ErrorCode.VALIDATION_ERROR, message)
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    /**
     * 处理参数校验异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ApiResponse<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        String message = fieldErrors.stream()
                .map(error -> error.getField() + ": " + error.getDefaultMessage())
                .collect(Collectors.joining(", "));
        log.warn("参数校验异常: {}", message);
        return ApiResponse.fail(ErrorCode.VALIDATION_ERROR, message)
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    /**
     * 处理约束违反异常
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ApiResponse<Void> handleConstraintViolationException(ConstraintViolationException e, HttpServletRequest request) {
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        String message = violations.stream()
                .map(violation -> violation.getPropertyPath() + ": " + violation.getMessage())
                .collect(Collectors.joining(", "));
        log.warn("约束违反异常: {}", message);
        return ApiResponse.fail(ErrorCode.VALIDATION_ERROR, message)
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    /**
     * 处理缺少请求参数异常
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ApiResponse<Void> handleMissingServletRequestParameterException(MissingServletRequestParameterException e, HttpServletRequest request) {
        log.warn("缺少请求参数: {}", e.getMessage());
        return ApiResponse.fail(ErrorCode.PARAM_ERROR, "缺少请求参数: " + e.getParameterName())
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    /**
     * 处理参数类型不匹配异常
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ApiResponse<Void> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request) {
        log.warn("参数类型不匹配: {}", e.getMessage());
        return ApiResponse.fail(ErrorCode.PARAM_ERROR, "参数类型不匹配: " + e.getName())
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    /**
     * 处理请求方法不支持异常
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    public ApiResponse<Void> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e, HttpServletRequest request) {
        log.warn("请求方法不支持: {}", e.getMessage());
        return ApiResponse.fail(ErrorCode.METHOD_NOT_ALLOWED, "不支持" + e.getMethod() + "请求方法")
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    /**
     * 处理接口不存在异常
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ApiResponse<Void> handleNoHandlerFoundException(NoHandlerFoundException e, HttpServletRequest request) {
        log.warn("接口不存在: {}", e.getMessage());
        return ApiResponse.fail(ErrorCode.API_NOT_FOUND, "接口不存在: " + e.getRequestURL())
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    /**
     * 处理上传文件过大异常
     */
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ApiResponse<Void> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e, HttpServletRequest request) {
        log.warn("上传文件过大: {}", e.getMessage());
        return ApiResponse.fail(ErrorCode.PARAM_ERROR, "上传文件过大，最大允许大小: " + e.getMaxUploadSize() + " bytes")
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    /**
     * 处理数据库异常
     */
    @ExceptionHandler(SQLException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ApiResponse<Void> handleSQLException(SQLException e, HttpServletRequest request) {
        log.error("数据库异常: {}", e.getMessage(), e);
        return ApiResponse.fail(ErrorCode.SYSTEM_ERROR, "数据库操作异常")
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    // ================ 通用异常处理 ================
    
    /**
     * 处理运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ApiResponse<Void> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
        log.error("运行时异常: {}", e.getMessage(), e);
        return ApiResponse.fail(ErrorCode.SYSTEM_ERROR, "系统运行时异常")
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    /**
     * 处理未知异常
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ApiResponse<Void> handleException(Exception e, HttpServletRequest request) {
        log.error("未知异常: {}", e.getMessage(), e);
        return ApiResponse.fail(ErrorCode.SYSTEM_ERROR, "系统内部错误")
                .path(request.getRequestURI())
                .traceId(getTraceId(request));
    }
    
    /**
     * 获取请求的追踪ID
     */
    private String getTraceId(HttpServletRequest request) {
        return request.getHeader("X-Trace-Id");
    }
} 